#include "picture.h"
//判断图片格式
enum enumread tupiangeshi(const char *p)
{
    if(strstr(p,".bmp"))
    return bmp;
    else if(strstr(p,".jpg") || strstr(p,".jpeg"))
    return jpg;
    else
    return buzhichi;
}


//jpg解码
void jpg2rgb(const char *jpgdata, size_t jpgsize,struct tupian_info *jpg)
{
    // 1，声明解码结构体，以及错误管理结构体
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    // 2，使用缺省的出错处理来初始化解码结构体
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);

    // 3，配置该cinfo，使其从 jpgdata 中读取jpgsize个字节
    //    这些数据必须是完整的JPEG数据
    jpeg_mem_src(&cinfo, jpgdata, jpgsize);

    // 4，读取JPEG文件的头，并判断其格式是否合法
    if(!jpeg_read_header(&cinfo, true))
    {
        fprintf(stderr, "jpeg_read_header failed: "
            "%s\n", strerror(errno));
        return;
    }

    // 5，开始解码
    jpeg_start_decompress(&cinfo);
    

    jpg->wide        = cinfo.output_width;
    jpg->high        = cinfo.output_height;
    jpg->bpp         = cinfo.output_components*8;
    jpg->tosize      = jpg->wide*jpg->high*jpg->bpp/8;

    int row_stride = cinfo.output_width * cinfo.output_components;

    // 7，根据图片的尺寸大小，分配一块相应的内存rgbdata
    //    用来存放从jpgdata解码出来的图像数据
    unsigned long linesize = cinfo.output_width * cinfo.output_components;
    unsigned long rgbsize  = linesize * cinfo.output_height;
    char *rgbdata = calloc(1, rgbsize);
    if(rgbdata == NULL)
    {
        printf("内存分配失败!");
        exit(0);
    }

    // 8，循环地将图片的每一行读出并解码到rgb_buffer中
    int line = 0;
    while(cinfo.output_scanline < cinfo.output_height)
    {
        unsigned char *buffer_array[1];
        buffer_array[0] = rgbdata + cinfo.output_scanline * linesize;
        jpeg_read_scanlines(&cinfo, buffer_array, 1);
    }

    // 9，解码完了，将jpeg相关的资源释放掉
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    //jpg->men = calloc(1,jpg->tosize);
    jpg->men = rgbdata;
}
//获取图片数据
void tupiansj(enum enumread a,struct tupian_info *p,const char *q)
{
    if(a == jpg)
    {
        FILE *fp = fopen(q,"r");
        struct stat jpgstat;
        stat(q,&jpgstat);
        char *jpgrpg = calloc(1,jpgstat.st_size);
        if(jpgrpg == NULL)
        {
            printf("内存申请失败:%s\n",strerror(errno));
            exit(0);
        }
        int n = fread(jpgrpg,jpgstat.st_size,1,fp);
        if(n!=1)  
        {
            printf("读取jpg图片数据失败!\n");
            exit(0);
        }
        fclose(fp);

        jpg2rgb(jpgrpg,jpgstat.st_size,p);

    }
    if(a == bmp)
    {
        struct stat bmpstat;
        stat(q,&bmpstat);
        int fbmp = open(q,O_RDWR);
        struct bitmap_header header;
	    struct bitmap_info info;
        read(fbmp,&header,sizeof(struct bitmap_header));
        read(fbmp,&info,sizeof(struct bitmap_info));
        close(fbmp);
        p->wide   = info.width;
        p->high   = info.height;
        p->bpp    = info.bit_count;
        p->tosize = header.size;
        FILE *fpbmp = fopen(q,"r");
        p->men = calloc(1,p->tosize);
        memset(p->men,0,p->tosize);
        int n = fread(p->men,p->tosize,1,fpbmp);
        if(n!=1)
        {
            printf("读取bmp图片数据失败!\n");
            exit(0);
        }
        fclose(fpbmp);
    }
}
//显示图片
void displaytu(enum enumread a,struct lcd_info *lcd,struct tupian_info *tupian)
{
    //优化显示时的问题
    //设置可见区
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    ioctl(lcd->fb,FBIOGET_VSCREENINFO,&vinfo);
    ioctl(lcd->fb,FBIOGET_FSCREENINFO,&finfo);


    //居中，缩小
    int x = 0,y = 0,x1 = 0,y1 = 0;    
    if(lcd->wide > tupian->wide)
    {
        x = lcd->wide - tupian->wide;
        if(lcd->high > tupian->high)
        {
            y = lcd->high - tupian->high;
        }
        else if(lcd->high < tupian->high)
        {
            y1 = tupian->high -lcd->high;
        }
    }
    else if(lcd->wide < tupian->wide)
    {
        x1 = tupian->wide - lcd->wide;
        if(lcd->high > tupian->high)
        {
            y = lcd->high - tupian->high;              
        }
        else if(lcd->high < tupian->high)
        {
            y1 = tupian->high -lcd->high;
        }         
    }

    //jpg图片显示
    if(a == jpg)
    {
    //将初始可见区移到屏幕下方
    vinfo.xoffset = 0;
    vinfo.yoffset = 0 + lcd->high;
    ioctl(lcd->fb,FBIOPAN_DISPLAY,&vinfo);

    for(int j=0 ; j<tupian->high && j<lcd->high; j++)
    {
        //偏移量       
        int moffset = tupian->wide*tupian->bpp/8*(j+(y1/2));
        int loffset = lcd->wide*lcd->bpp/8 * (j+(y/2));
        //拷贝像素
        for(int i=0; i<tupian->wide && i<lcd->wide; i++)
        {
            memcpy(lcd->men + (x/2)*4 + 4*i + loffset+0, tupian->men + (x1/2)*3 +3*i + moffset+2, 1);
            memcpy(lcd->men + (x/2)*4 + 4*i + loffset+1, tupian->men + (x1/2)*3 +3*i + moffset+1, 1);
            memcpy(lcd->men + (x/2)*4 + 4*i + loffset+2, tupian->men + (x1/2)*3 +3*i + moffset+0, 1);
        }
    }    
    //图片加载完成后将可见区移回到屏幕
    vinfo.xoffset = 0;
    vinfo.yoffset = 0;
    ioctl(lcd->fb,FBIOPAN_DISPLAY,&vinfo);
    }
    if(a == bmp)
    {
        //将初始可见区移到A       
        vinfo.xoffset = 0;
        vinfo.yoffset = 0 + lcd->high;
        ioctl(lcd->fb,FBIOPAN_DISPLAY,&vinfo);
        //计算无效字节
        int wx = (4 - (tupian->wide*tupian->bpp/8)%4)%4;

        int d  = tupian->bpp/8;
        int l  = lcd->bpp/8;

        char *tmp = tupian->men + (tupian->high - (y1/2) - 1)*(tupian->wide*d + wx);
        for(int i=0;i<lcd->high && i<tupian->high ;i++)
        {
            for(int j=0;j<lcd->wide && j<tupian->wide;j++)
            memcpy(lcd->men+(x/2)*l+j*l+(y/2)*lcd->wide*l+i*lcd->wide*l,tmp+(x1/2)*d+j*d,d);
            
            tmp = tmp - (tupian->wide*d + wx);
        }        
        //图片加载完成后将可见区移回到B
        vinfo.xoffset = 0;
        vinfo.yoffset = 0;
        ioctl(lcd->fb,FBIOPAN_DISPLAY,&vinfo);
    }
}
//白屏
void baiping(struct lcd_info *lcd)
{
    uint32_t bai[] = {0x00FFFFFF};
    int y = lcd->high*lcd->wide*lcd->bpp/8;
    for(int i=0;i < lcd->high;i++)
    {
        for(int j=0;j < lcd->wide;j++)
        memcpy(lcd->men+ y + i*4*lcd->wide + j*4,&bai[0],4);
    }
}

//加载效果,jpg图片
void jiazai(struct lcd_info *lcd,struct tupian_info *dt)
{
    int y = (lcd->high - dt->high)/2;
    int lcdpy = lcd->wide*lcd->bpp/8;
    int dtpy  = dt->wide*dt->bpp/8;
    for(int i=0;i<lcd->wide && i<dt->wide;i++)
    {
    //打印一列
    for(int j=0;j<lcd->high && j<dt->high;j++)
    {
    memcpy(lcd->men+y*lcdpy+j*lcdpy+i*lcd->bpp/8+0,dt->men+j*dtpy+i*dt->bpp/8+2,1);
    memcpy(lcd->men+y*lcdpy+j*lcdpy+i*lcd->bpp/8+1,dt->men+j*dtpy+i*dt->bpp/8+1,1);
    memcpy(lcd->men+y*lcdpy+j*lcdpy+i*lcd->bpp/8+2,dt->men+j*dtpy+i*dt->bpp/8+0,1);
    }
    //利用延时试验动态效果
    usleep(50*100);
    }
}
